#!/usr/bin/env python
# By: Kelcey Damage, 2012 & Kraig Amador, 2012
# RoyalYang modified on 20130228

apiKey = 'vuGobuYCYmZfoAkR53mCgn5rVT3jaYQmXOj1gs_-i-ZTIhdQ3i4GtfxpnLWXD57OmQd1wYlVwSL3HpEDw0_T-A'
secret = 'Du_8VSPTi1_Jyg4q0Nf8zhOQkBuVAvQmvNCOhmeVsPtBaEQSWHfBXxg4MwY6PJhz4e8U5prUFdHbxnCILJvbAw'
#api_url = 'https://localhost:8443/client/api'
##max retry startvm count
MRC = 2 

method = 'https' #(http or https)
address = '127.0.0.1'
port = 8443
api_url = method+'://'+address+':'+str(port)+'/client/api/'
#print api_url
import hashlib, hmac, string, base64, urllib
import json, urllib ,time,threading,sys,socket,traceback
class SignedAPICall(object):
    def __init__(self, api_url, apiKey, secret):
        self.api_url = api_url
        self.apiKey = apiKey
        self.secret = secret

    def request(self, args):
        args['apiKey'] = self.apiKey

        self.params = []
        self.__sort_request(args)
        self.__create_signature()
        self.__build_post_request()

    def __sort_request(self, args):
        keys = sorted(args.keys())

        for key in keys:
            self.params.append(key + '=' + urllib.quote_plus(args[key]))

    def __create_signature(self):
        self.query = '&'.join(self.params)
        digest = hmac.new(
            self.secret,
            msg=self.query.lower(),
            digestmod=hashlib.sha1).digest()
        self.signature = base64.b64encode(digest)

    def __build_post_request(self):
        self.query += '&signature=' + urllib.quote_plus(self.signature)
        self.value = self.api_url + '?' + self.query

class CloudStack(SignedAPICall):
    def __getattr__(self, name):
        def handlerFunction(*args, **kwargs):
            if kwargs:
                return self._make_request(name, kwargs)
            return self.__make_request(name, args[0])
        return handlerFunction

    def __http_get(self, url):
        response = urllib.urlopen(url)
        return response.read()

    def __make_request(self, command, args):
        args['response'] = 'json'
        args['command'] = command
        self.request(args)
        data = self.__http_get(self.value)
        # The response is of the format {commandresponse: actual-data}

        key = command.lower() + "response"
        return json.loads(data)[key]

class check_async_job(threading.Thread):
        global jobid
        def __init__(self, jobid):
                threading.Thread.__init__(self)
                self.thread_jobid = jobid
                self.thread_stop = False
        def run(self): #Overwrite run() method, put what you want the thread do here
                cnt=0
                while not self.thread_stop:
                        jobstatus=0
                        request = {'jobid': self.thread_jobid}
                        #print self.thread_jobid
                        if cnt<10 :
                                result = api.queryAsyncJobResult(request)
                                cnt+=1
                                time.sleep(5)
                                if result.has_key('jobstatus') and result.has_key('jobstatus')==1:
                                        #print "job %s is done\n"%(self.thread_jobid)
                                        self.thread_stop = True                 
                        else :
                                print "timeout while checking jobid %d"%(self.thread_jobid)
                                self.thread_stop = True
        def stop(self):
                self.thread_stop = True

#check if api port is open
def checkcon():
    confailed=1
    exstr=''
    conter=0
    while confailed and conter<5:
        sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sk.settimeout(1)
        try:
            sk.connect((address,port))
            confailed=0
            print 'Server port is OK!'
            sk.close()
        except Exception:
            print 'Server port is not connect!'
            exstr = traceback.format_exc()
            print exstr
            sk.close()
            time.sleep(10)
            conter=conter+1
    if(conter>=5):
        exit(1)

#Usage
#api = CloudStack(api_url, apiKey, secret)

#close vms in project
def closevmsinpro():
    request = { 'listall':'true' }
    result = api.listProjects(request)
    if result.has_key('count'):
        for project in result['project']:
            request1 = {'listall': 'true','projectid': project['id']}
            result = api.listVirtualMachines(request1)
                #print api.value
            if result.has_key('count'):
                #stop virtual machines
                #print api.value
                for vm in result['virtualmachine']:
                    if (vm['state']=='Running'):
                        print "Stopping %s" %vm['name']
                        request = {'id': vm['id']}
                        result = api.stopVirtualMachine(request)
                        if result.has_key('jobid') :
                            jobid=result['jobid']
                            thread1=check_async_job(jobid).start()
            elif(len(result)==0):
                print "No VM needs to be stopped in project %s" % project['id']
            else:
                print "shutdown VirtualMachines Failed in project %s" % project['id']
                #print api.value
                exit(1)
            result = api.listRouters(request1)
            hasrunrt = 0
            #print "api url", api.value
            if result.has_key('router') :
                for vm in result['router']:
                    if vm['state']=='Running' :
                        hasrunrt=1
                        print "Stopping %s" % vm['name']
                        request = {'id': vm['id']}
                        result = api.stopRouter(request)
                        if result.has_key('jobid') :
                            jobid=result['jobid']
                            thread1=check_async_job(jobid).start()
                        else:
                            print "shutdown VRouter Failed"
                if(hasrunrt==0) :
                    print "No VRouter needs to be stopped in project %s" % project['id']
    else:
        print "no project"

#start zone
def startzone():
    request = { }
    result = api.listZones(request)
    #print api.value
    if result.has_key('zone') :
        isneedstart = 'false'
        for zone in result['zone']:
            if zone['allocationstate']=='Disabled':
                isneedstart = 'true'
                #print zone['allocationstate']
                print "Enabling %s" % zone['name']
                request = {'id': zone['id'], 'allocationstate' : 'Enabled'}
                result = api.updateZone(request)
        print 'Please wait for a moment while cloudstack starting......'
        if isneedstart=='false':
                print "no Zone needs to be Enabled"
    else:
            print "no Zone needs to be Enabled"

#check sysvm_onstart
def chksysvm():
        isneedwait=0
        request = {'listall': 'true'}
        result = api.listSystemVms(request)
        if result.has_key('count') :
            for vm in result['systemvm']:
                if vm['state']=='Stopped' :
                    isneedwait=1
            if isneedwait==0 :
                print "Start Sysvms OK!!"
            elif isneedwait==1 :
                print "wait once more"
                time.sleep(5)
                chksysvm()
        else:
                print "starting SystemVms Failed"
                exit(1)
    

#start nginx-vm
def startnginx():
    print "waiting for starting nginx"
    time.sleep(180)
    request = {'id':nginx_vm_id}
    api.startVirtualMachine(request)
    print "Done!!\n"
    print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))

#read vm_list
def autostart_vms():
    file = open("/root/autostart_vms.txt")
    while 1:
        lines = file.readlines(100000)
        if not lines:
            break
        for line in lines:
            line=line.strip('\n')
            if len(line)==36 and line.count('#')==0:
                startvm(line)
                time.sleep(1)
    print "Done!!\n"
    print time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))

#start vm
def startvm(vm_id):
    print "start vm %s" %vm_id
    request = {'id':vm_id}
    result=api.startVirtualMachine(request)
    if result.has_key('jobid') :
        jobid=result['jobid']
        thread1=check_async_job(jobid).start()

#check N retry startvm
def autochkvms():
    count=0
    for i in range(1,MRC):
        file = open("/root/autostart_vms.txt")
        while 1:
            lines = file.readlines(100000)
            if not lines:
                break
            for line in lines:
                line=line.strip('\n')
                if len(line)==36 and line.count('#')==0:
                    chknsvm(line)
                    time.sleep(1)
        #wait for next check
        time.sleep(60)

def chknsvm(vm_id):
    request = {'id':vm_id}
    result=api.listVirtualMachines(request)
    if result.has_key('count'):
        for vm in result['virtualmachine']:
            if (vm['state']=='Stopped'):
                print "Trying to restart vm  %s" % vm['name']
                startvm(vm['id'])
#stop zone
def stopzone() :
    request = { }
    result = api.listZones(request)
    #print api.value
    if result.has_key('zone') :
        isneedstop = 'false'
        for zone in result['zone']:
            if zone['allocationstate']=='Enabled':
                isneedstop = 'true'
                print zone['allocationstate']
                print "Disabling %s" % zone['name']
                request = {'id': zone['id'], 'allocationstate' : 'Disabled'}
                result = api.updateZone(request)
            if isneedstop=='false':
                print "no Zone needs to be Disabled"
    else:
        print "no Zone needs to be Disabled"

#stop vms
def stopvms() :
        request = {'listall': 'true'}
        result = api.listVirtualMachines(request)
        #print api.value
        if result.has_key('count'):
                #stop virtual machines
                #print api.value
            for vm in result['virtualmachine']:
                if (vm['state']=='Running'):
                    print "Stopping %s" %vm['name']
                    request = {'id': vm['id']}
                    result = api.stopVirtualMachine(request)
                    if result.has_key('jobid') :
                        jobid=result['jobid']
                        thread1=check_async_job(jobid).start()
#               time.sleep(5)
#                                thread1.stop()
                        #print "api url", api.value
        elif(len(result)==0):
                print "No VM needs to be stopped"
        else:
                print "shutdown VirtualMachines Failed"
                exit(1)

#stop system vms
def stopsysvm() :
        request = {'listall': 'true'}
        result = api.listSystemVms(request)
        if result.has_key('count') :
            for vm in result['systemvm']:
                if vm['state']=='Running' :
                    print "Stopping %s" % vm['name']
                    #request = {'id': vm['id']}
                    request = {'id': vm['id']}
                    result = api.stopSystemVm(request)
                    if result.has_key('jobid') :
                        jobid=result['jobid']
                        thread1=check_async_job(jobid).start()
                        #print "api url", api.value
        elif(len(result)==0):
                print "No SysVM needs to be stopped"
        else:
                print "shutdown SystemVms Failed"
                exit(1)

#stop vrouter
def stopVrouter():
        request = {'listall': 'true'}
        result = api.listRouters(request)
        hasrunrt = 0
        #print "api url", api.value
        if result.has_key('router') :
            for vm in result['router']:
                if vm['state']=='Running' :
                    hasrunrt=1
                    print "Stopping %s" % vm['name']
                    request = {'id': vm['id']}
                    result = api.stopRouter(request)
                    if result.has_key('jobid') :
                        jobid=result['jobid']
                        thread1=check_async_job(jobid).start()
                        #time.sleep(5)
                        #print "api url", api.value
        else:
            print "shutdown VRouter Failed"
        if(hasrunrt==0) :
            print "No VRouter needs to be stopped"

#check and wait
def chknwait() :
     while True:
         if(threading.activeCount()-1 != 0):
             print "wait while sysvms,vms and vrouters stopping"
             time.sleep(2)
             continue
         else:
             print "CloudStack has all jobs done!!"
             #time.sleep(10)
             exit()

#main method
if __name__=='__main__':
    api = CloudStack(api_url, apiKey, secret)
    if len(sys.argv) < 2:
        print 'please input whether -shutdown or -startup\n'  
    else:
        for i in sys.argv[1:]:  
            if(i=='-shutdown'):
                checkcon()
                stopzone()
                closevmsinpro()
                stopvms()
                stopsysvm()
                stopVrouter()
                chknwait()
            elif(i=='-startup'):
                checkcon()
                startzone()
                time.sleep(180)
                chksysvm()
                autostart_vms()
                time.sleep(180)
                autochkvms()
                chknwait()
            elif(i=='-startvm' and len(sys.argv)>1):
                #print '%s' %sys.argv[2]
                startvm(sys.argv[2])
                exit()
            elif(i=='-autostart'):
                autostart_vms()
                time.sleep(30)
                autochkvms()
                chknwait()
            else:
                print 'Parameter is not supported!!Check your input.\n'
                exit()
